#ifndef MEMQUEUE_H_
#define MEMQUEUE_H_

#include <assert.h>
#include "SafeQueue.hh"
#include "Synchronized.hh"
#include <lagniappe/RCon.h>
#include <map>

class memQueue : public Synchronized
{
private:
    std::map<std::string, SafeQueue<lagniappe::RCon *> *> coreQueues;
    uint32_t work;
    std::map<std::string, SafeQueue<lagniappe::RCon *> *>::iterator mapIter;
public:
    memQueue() : work(0) {}
    virtual ~memQueue() {}
    virtual unsigned long getFreeQueues() {
        return 20 - coreQueues.size();
    }
    void registerQueue(std::string queueName) {
        Synchronized::Scope mutex(this);
        if(coreQueues.find(queueName) == coreQueues.end()) {
	  coreQueues[queueName] = new SafeQueue<lagniappe::RCon *>();
	  mapIter = coreQueues.begin();
	}
        notifyAll();
    }
    void deleteQueue(std::string queueName) {
        SafeQueue<lagniappe::RCon *> * target = coreQueues[queueName];
        delete target;
        coreQueues[queueName] = NULL;
        coreQueues.erase(queueName);
    }
    //void push(lagniappe::RCon * rc) {assert(rc != NULL); coreQueue.push(rc);}
    void push(lagniappe::RCon *rc) {
        assert(!coreQueues.empty());
        announceWork();
        //std::cerr<< rc->getPort() << std::endl;
        SafeQueue<lagniappe::RCon *> * target = coreQueues[rc->getPort()];
        assert(target != NULL);
        target->push(rc);
    }
    //lagniappe::RCon * pop() {lagniappe::RCon * rc = coreQueue.pop(); return rc;}
    lagniappe::RCon * pop() {
        waitForQueues();
        SafeQueue<lagniappe::RCon *> * target = mapIter->second;
        lagniappe::RCon * ret = NULL;
        while(ret == NULL) {
            waitForWork();
            ret = target->peek();
            if(ret != NULL /*&& ret->getOp()->pred(ret->getPort())*/) {
		std::cerr << "Got inside" << std::endl;
                target->pop();
                takeWork();
                mapIter++;
                if(mapIter == coreQueues.end()) {
                    mapIter = coreQueues.begin();
                }
            }
            else {
		ret = NULL;
                mapIter++;
                if(mapIter == coreQueues.end()) {
                    mapIter = coreQueues.begin();
                }
                target = mapIter->second;
            }
        }
        return ret;
    }
    void waitForQueues() {
        Synchronized::Scope mutex(this);
        while(coreQueues.empty()) {
            wait();
        }
    }
    void waitForWork() {
        Synchronized::Scope mutex(this);
        while(work == 0) {
            wait();
        }
    }
    void announceWork() {
        Synchronized::Scope mutex(this);
        work++;
        notifyAll();
    }
    void takeWork() {
        Synchronized::Scope mutex(this);
        work--;
        assert(work >= 0);
        notifyAll();
    }
    //bool empty() {}
};

#endif // MEMQUEUE_H_
